package com.stop.think.shiro.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.paypal.http.HttpResponse;
import com.paypal.orders.*;
import com.stop.think.shiro.common.PayPalConfig;
import com.stop.think.shiro.dao.OrderRecordDao;
import com.stop.think.shiro.dao.entity.OrderRecord;
import com.stop.think.shiro.service.paypal.PayPalClient;
import com.stop.think.shiro.service.paypal.PayPalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
public class OrderRecordService {

    @Resource private OrderRecordDao orderRecordDao;
    @Resource private PayPalService payPalService;

    @Value("${domain.url}")
    private String domainUrl;

    public JSONObject createPayOrder() {
        OrderRecord record = new OrderRecord();
        record.setId(IdUtil.getSnowflake().nextIdStr());
        record.setCreateDate(LocalDateTime.now());
        record.setName("测试商铺");
        record.setMoney(BigDecimal.ONE);
        record.setCurrencyCode("USD"); // 币种
        record.setStatus(OrderRecord.STATUS_ING);
        JSONObject retJson = new JSONObject();
        try {
            retJson.set("approveUrl", this.createPayPalOrder(record));
        } catch (IOException e) {
            log.error("创建订单错误", e);
            // 这个地方也可以进行重试
        }
        orderRecordDao.save(record);
        return retJson;
    }

    private String createPayPalOrder(OrderRecord orderRecord) throws IOException {
        OrdersCreateRequest request = new OrdersCreateRequest();
        request.prefer("return=representation");
        request.requestBody(buildRequestBody(orderRecord));
        //3. Call PayPal to set up a transaction
        HttpResponse<Order> response = PayPalClient.client().execute(request);
        String approveUrl = "";
        if (response.statusCode() == 201) {
            System.out.println("Status Code: " + response.statusCode());
            System.out.println("Status: " + response.result().status());
            System.out.println("Order ID: " + response.result().id());
            System.out.println("Links: ");
            // 保存支付订单号
            orderRecord.setPayOrdNo(response.result().id());
            for (LinkDescription link : response.result().links()) {
                System.out.println("\t" + link.rel() + ": " + link.href() + "\tCall Type: " + link.method());
                if (link.rel().equals("approve")) {
                    approveUrl = link.href();
                }
            }
            System.out.println("Total Amount: " + response.result().purchaseUnits().get(0).amountWithBreakdown().currencyCode()
                    + " " + response.result().purchaseUnits().get(0).amountWithBreakdown().value());
        }
        return approveUrl;
    }

    private OrderRequest buildRequestBody(OrderRecord orderRecord) {
        OrderRequest orderRequest = new OrderRequest();
        orderRequest.checkoutPaymentIntent(PayPalConfig.INTENT);

        ApplicationContext context = new ApplicationContext()
                // 商家名称，展示在支付界面
                .brandName(PayPalConfig.BRAND_NAME)
                .landingPage(PayPalConfig.LANDING_PAGE)
                .cancelUrl(domainUrl + "/pay/result") // 取消返回地址
                .returnUrl(domainUrl + "/pay/result") // 支付成功返回地址
                .userAction(PayPalConfig.USER_ACTION)
                .shippingPreference(PayPalConfig.SHIPPING_PREFERENCE);
        orderRequest.applicationContext(context);

        List<PurchaseUnitRequest> purchaseUnitRequests = new ArrayList<PurchaseUnitRequest>();
        PurchaseUnitRequest unitRequest = new PurchaseUnitRequest()
                .customId(orderRecord.getId() + "")
                // 发票标识
                .invoiceId(orderRecord.getId() + "")
                .amountWithBreakdown(
                        new AmountWithBreakdown()
                                .currencyCode("USD")
                                .value(NumberUtil.decimalFormat("###.00", orderRecord.getMoney()))
                );
        purchaseUnitRequests.add(unitRequest);
        orderRequest.purchaseUnits(purchaseUnitRequests);
        return orderRequest;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean payNotify(String payOrdNo, boolean cancelFlag) {
        if (StrUtil.isBlank(payOrdNo)) {
            return false;
        }
        Optional<OrderRecord> orderRecordOptional = orderRecordDao.findByPayOrdNo(payOrdNo);
        if (!orderRecordOptional.isPresent()) {
            log.warn("单号错误：" + payOrdNo);
            return false;
        }
        OrderRecord record = orderRecordOptional.get();
        if (!record.getStatus().equals(OrderRecord.STATUS_ING)) {
            return true;
        }
        if (cancelFlag) {
            record.setPayDate(LocalDateTime.now());
            record.setMark("取消支付");
            orderRecordDao.save(record);
            return false;
        }
        try {
            // 核销资金
            payPalService.captureOrder(payOrdNo);
        } catch (IOException e) {
            log.error("支付核销失败：" + payOrdNo, e);
            return false;
        }
        record.setPayDate(LocalDateTime.now());
        record.setMark("");
        record.setStatus(OrderRecord.STATUS_SUC);
        orderRecordDao.save(record);
        return true;
    }
}
